package com.nightpiter.view.dialogs;

import static com.nightpiter.controller.log.Logger.log;
import android.content.Context;
import android.content.DialogInterface;
import android.view.View;
import android.view.ViewInflate;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.nightpiter.R;
import com.nightpiter.controller.algorithms.MetroRouterState;
import com.nightpiter.controller.algorithms.Route;
import com.nightpiter.model.objects.Station;
import com.nightpiter.model.objects.Time;

/**
 * InfoDialog class.
 * 
 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
 */
public class InfoDialog extends LinearLayout implements View.OnClickListener,
		DialogInterface.OnClickListener, ItemsDialog.Listener,
		AdapterView.OnItemSelectedListener {

	/**
	 * Listener interface. Should be implemented by any class that would receive
	 * notifications from this View
	 * 
	 * @author Eldar Abusalimov (eldar.abusalimov@gmail.com)
	 */
	public interface Listener {

		public void onRouteToDefine(Station toStation);

		public void onRouteFromDefine(Station fromStation);

		public void onRouteSelect(Route route);

		public void onStationSelect(Station station);

		public void onDialogHide();

	}

	/** the subscriber that would be notified about most of events */
	private Listener listener;

	/** the dialog itself */
	private TransparentDialog contentView;

	/** station info */
	private TextView nameText, infoText;

	/** routes info */
	private TextView routeCountText, routeDestinationText;

	/** drop-down with available routes */
	private Spinner routesSpinner;

	/** common buttons */
	private Button toggleButton, hideButton;

	/** station selection dialog */
	private StationsDialog stationsDialog;

	/** icon in the row */
	private StationIcon stationIcon;

	/** the station, info of which is shown */
	private Station currentStation;

	/** the currentRoute shown on the screen */
	private Route currentRoute;

	/** all available routes */
	private Route[] routes;

	/** the other end of the route */
	private Station destinationStation;

	/** mode - router or stationInfo */
	private boolean routerToggle = false;

	/** indicates the router state */
	private boolean routerPrepared = false;

	/** this would be shown when routerToggle is off */
	private RelativeLayout stationInfoLayout;

	/** this would be shown when routerToggle is on */
	private LinearLayout routerInfoLayout, routerCountLayout;

	/** adapter to use when preparing the router */
	private ArrayAdapter<String> emptyAdapter;

	/**
	 * @param context
	 */
	public InfoDialog(Context context) {
		super(context);

		ViewInflate.from(getContext()).inflate(R.layout.info, this, null);

		this.contentView = (TransparentDialog) findViewById(R.id.info_dialog);

		this.nameText = (TextView) findViewById(R.id.text_station_name);
		this.infoText = (TextView) findViewById(R.id.text_station_info);
		this.routeCountText = (TextView) findViewById(R.id.text_router_count);
		this.routeDestinationText = (TextView) findViewById(R.id.text_router_destination);

		this.hideButton = (Button) findViewById(R.id.button_hide);
		this.toggleButton = (Button) findViewById(R.id.button_toggle);

		this.stationInfoLayout = (RelativeLayout) findViewById(R.id.layout_station_info);
		this.routerInfoLayout = (LinearLayout) findViewById(R.id.layout_router_info);
		this.routerCountLayout = (LinearLayout) findViewById(R.id.layout_router_count);

		this.hideButton.setOnClickListener(this);
		this.toggleButton.setOnClickListener(this);

		this.routesSpinner = (Spinner) findViewById(R.id.spinner_routes);
		this.routesSpinner.setOnItemSelectedListener(this);
		this.emptyAdapter = new ArrayAdapter<String>(getContext(),
				android.R.layout.simple_spinner_item);
		this.emptyAdapter
				.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		this.routesSpinner.setAdapter(this.emptyAdapter);
		this.routesSpinner.setEnabled(false);

		this.stationsDialog = new StationsDialog(getContext());
		this.stationsDialog.setListener(this);

		this.stationIcon = (StationIcon) findViewById(R.id.station_icon);

		updateView();
	}

	/**
	 * update the view
	 */
	private void updateView() {
		if (routerToggle) {
			updateRouteInfo();
		} else {
			updateStationInfo();
		}
	}

	/**
	 * update data in stations dialog
	 */
	private void updateStationInfo() {
		stationInfoLayout.setVisibility(VISIBLE);
		routerInfoLayout.setVisibility(INVISIBLE);
		routerCountLayout.setVisibility(GONE);
		this.toggleButton.setText("Search routes from this station");

		if (currentStation != null) {
			Time openTime = currentStation.getOpenTime();
			Time closeTime = currentStation.getCloseTime();

			infoText.setText("");
			infoText.append(getContext().getText(R.string.station_open));
			infoText.append(openTime.toString());
			infoText.append("   ");
			infoText.append(getContext().getText(R.string.station_close));
			infoText.append(closeTime.toString());

			nameText.setText(currentStation.getName());
			stationIcon.setStation(currentStation);
		}
		setTextFields("", "");
	}

	/**
	 * update data in routes dialog
	 */
	private void updateRouteInfo() {
		stationInfoLayout.setVisibility(INVISIBLE);
		routerInfoLayout.setVisibility(VISIBLE);
		routerCountLayout.setVisibility(VISIBLE);
		this.toggleButton.setText("Back");

		if (!routerPrepared) {
			// log("router is not yet prepared");
			this.routesSpinner.setAdapter(emptyAdapter);
			this.routesSpinner.setEnabled(false);

		} else if (destinationStation == null) {
			log("router prepared, but destination is not selected");
			setTextFields("please select", "a destination");
			this.routesSpinner.setAdapter(emptyAdapter);
			this.routesSpinner.setEnabled(false);

		} else if (routes == null) {
			log("destination selected, but routes are not yet retrieved");
			setTextFields("searching", destinationStation.getName());
			this.routesSpinner.setAdapter(emptyAdapter);
			this.routesSpinner.setEnabled(false);

		} else if (routes.length == 0) {
			log("there are no routes to the destination");
			setTextFields("no routes to", destinationStation.getName());
			this.routesSpinner.setAdapter(emptyAdapter);
			this.routesSpinner.setEnabled(false);

		} else if (currentRoute == null) {
			assert false;
			log("WTF? seriously!");

		} else {
			log("regular view of router dialog");

			// formating time and routes
			String routesCount = "";
			if (routes.length == 1) {
				routesCount = "there is 1 route to";
			} else {
				routesCount = "there are " + routes.length + " routes to";
			}
			setTextFields(routesCount, destinationStation.getName());

		}
	}

	/**
	 * helper to set values of TextViews
	 * 
	 * @param countText
	 * @param destinationText
	 */
	private void setTextFields(String countText, String destinationText) {
		routeCountText.setText(countText);
		routeDestinationText.setText(destinationText);
	}

	/**
	 * user has clicked a buttons
	 */
	public void onClick(View targetView) {
		if (targetView == this.hideButton) {
			hide();

		} else if (targetView == this.toggleButton) {
			routerToggle = !routerToggle;
			if (listener != null) {
				if (routerToggle) {
					routerPrepared = false;
					routes = null;
					this.listener.onRouteFromDefine(currentStation);
				} else {
					this.listener.onRouteSelect(null);
				}
			}
			updateView();

		}
	}

	/**
	 * user has closed multiple stations dialog
	 * 
	 * @param dialog
	 * @param button
	 */
	public void onClick(DialogInterface dialog, int button) {
		if (dialog == this.stationsDialog) {
			log("multiple stations dialog closed");
		}
	}

	/**
	 * this will fire when a route would be selected
	 */
	@SuppressWarnings("unchecked")
	public void onItemSelected(AdapterView parent, View v, int position, long id) {
		if (parent == this.routesSpinner) {
			if (currentRoute != routes[position]) {
				currentRoute = routes[position];
				this.listener.onRouteSelect(currentRoute);
			}
		}
	}

	@SuppressWarnings("unchecked")
	public void onNothingSelected(AdapterView arg0) {
	}

	/**
	 * this will fire when one of multiple stations would be selected
	 */
	@SuppressWarnings("unchecked")
	public void onItemSelected(ItemsDialog itemsDialog, Object itemName) {
		if (itemsDialog == this.stationsDialog) {
			internalProcessStation((Station) itemName);
		}
	}

	/**
	 * a new station retrieved, process it
	 * 
	 * @param stations
	 * @param scrollToPoint
	 *            enable putting the point onto the center
	 */
	public void processStations(Station[] stations) {
		// TODO
		assert (stations != null);

		if (stations.length == 0) {
			if (!routerToggle) {
				hide();
			}
		} else if (stations.length == 1) {
			internalProcessStation(stations[0]);
		} else {
			this.stationsDialog.show(stations);
		}
	}

	/**
	 * show appropriate dialog about concrete station
	 * 
	 * @param station
	 */
	private void internalProcessStation(Station station) {
		if (!routerToggle) {
			currentStation = station;
			this.listener.onStationSelect(currentStation);
		} else {
			destinationStation = station;
			currentRoute = null;
			routes = null;
			this.listener.onRouteSelect(null);
			this.listener.onRouteToDefine(station);
		}
		contentView.show();
		updateView();
	}

	/**
	 * an array of routes retrieved, display info
	 * 
	 * @param routes
	 */
	public void processRoutes(Route[] routes) {
		this.routes = routes;
		if (routes != null) {
			if (routes.length > 0) {
				String[] routesInfoArray = new String[routes.length];
				for (int i = 0; i < routesInfoArray.length; i++) {
					Time time = new Time(routes[i].getTotalDistance());
					String timeStr = "";
					int roundedMinutes = time.getMinutes() + time.getMinutes()
							/ 30; // rounding
					// minuts
					int roundedHours = time.getHours();
					if (roundedMinutes == 60) {
						roundedMinutes = 0;
						roundedHours += 1;
					}

					if (roundedHours == 0) {
						if (roundedMinutes == 1)
							timeStr += " 1 minute";
						else
							timeStr += roundedMinutes + " minutes";
					} else {
						if (roundedHours == 1)
							timeStr += "1 hour";
						else
							timeStr += roundedHours + " hours";
						if (roundedMinutes != 0)
							if (roundedMinutes == 1) {
								timeStr += " 01 minute";
							} else {
								timeStr += " ";
								timeStr += Integer.toString(roundedMinutes)
										+ " minutes";
							}
					}

					String transferStr = "";
					int transfers = routes[i].getTransferHops();
					if (transfers == 0) {
						transferStr = "no transfers";
					} else if (transfers == 1) {
						transferStr = "1 transfer";
					} else {
						transferStr = transfers + " transfers";
					}
					routesInfoArray[i] = timeStr + " with " + transferStr;
				}
				ArrayAdapter<String> adapter = new ArrayAdapter<String>(
						getContext(), android.R.layout.simple_spinner_item,
						routesInfoArray);
				adapter
						.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
				routesSpinner.setAdapter(adapter);
				this.routesSpinner.setEnabled(true);
				currentRoute = routes[0];
				this.listener.onRouteSelect(currentRoute);

			} else {
				Toast
						.makeText(getContext(), "No ways found",
								Toast.LENGTH_LONG);
			}
		} else {
			log("ERROR! null routes array retrieved");
		}
		updateView();
	}

	public void onRouterStateChanged(MetroRouterState state) {
		if (state.getAction() != MetroRouterState.Action.IDLE) {
			routerPrepared = false;
			routes = null;
			setTextFields("Searching routes", "with " + state.getPass()
					+ " transfer hops");
		} else if (state.isReady()) {
			routerPrepared = true;
			destinationStation = null;
			Toast.makeText(getContext(), "Please select a destination",
					Toast.LENGTH_LONG);
		}
		updateView();
	}

	public void show() {
		contentView.show();
		if (listener != null) {
			this.listener.onStationSelect(currentStation);
			this.listener.onRouteSelect(currentRoute);
		}
	}

	public void hide() {
		contentView.hide();
		currentStation = null;
		currentRoute = null;
		routes = null;
		destinationStation = null;
		routerToggle = false;
		if (listener != null) {
			this.listener.onStationSelect(null);
			this.listener.onRouteSelect(null);
			this.listener.onDialogHide();
		}
	}

	/**
	 * subscribes to notifications
	 * 
	 * @param listener
	 *            the Listener
	 */
	public void setListener(Listener listener) {
		if (listener != null) {
			this.listener = listener;
		}
	}

}
